home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
v8n13.arc
/
CONVERT.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-06-10
|
22KB
|
427 lines
;------------------------------------------------------;
; Convert.com - Converts either a number or character ;
; to complementary radices. ;
; Decimal, Hexadecimal, Octal and Binary supported. ;
; PC Magazine * Michael J. Mefford ;
;------------------------------------------------------;
_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
ORG 100H
START: JMP MAIN
; DATA AREA
; ---------
SYNTAX DB CR,SPACE,SPACE,SPACE,CR,LF
COPYRIGHT DB "CONVERT 1.0 (C) 1989 Ziff Communications Co.",CR,LF
PROGRAMMER DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
DB "Syntax: CONVERT number[-number][radix] | "
DB QUOTES,"character(s)",QUOTES,CR,LF
DB "radix: b = binary, h = hexadecimal, o = octal",CR,LF
DB "default is decimal",LF,"$",CTRL_Z
CR EQU 13
LF EQU 10
CTRL_Z EQU 26
SPACE EQU 32
QUOTES EQU 34
BOX EQU 254
SPACE_CNT EQU 5
INVALID_MSG DB "Invalid parameter",CR,LF
DB "number range: 0 - 65535",CR,LF,"$"
RADIX_TYPE DB "HOB" ;Hex, octal, binary.
RADIX_CNT EQU $ - RADIX_TYPE
INPUT_CALLS DW DECIMAL_INPUT, HEX_INPUT, OCTAL_INPUT, BINARY_INPUT
CALLS_END EQU $ - 2
; CODE AREA
; ---------
;------------------------------------------------------------------------;
; Capitalize the parameters so a single compare for radices can be done. ;
;------------------------------------------------------------------------;
MAIN PROC NEAR
CLD ;All string moves forward.
CMP BYTE PTR DS:[80H],0 ;Are there parameters?
JNZ PARSE ;If yes, continue.
JMP ERROR_EXIT ;Else, exit with syntax message.
;------------------------------------------------------------------------------;
; Parse the parameters by looking for either carriage return, quotes, or dash. ;
;------------------------------------------------------------------------------;
PARSE: MOV DL,LF ;Print a linefeed just to first
CALL PRINT_CHAR ; to make our output look pretty.
MOV SI,82H ;Point to parameters again.
NEXT_INPUT: MOV BP,SI ;Start parameter start.
NEXT_PARSE: LODSB ;Get a byte.
CMP AL,CR ;Is it carriage return?
JZ EVALUATE ;If yes, done here.
CMP AL,QUOTES ;Is it quotes?
JZ CHARACTER ;If yes, character entry.
CMP AL,"-" ;Is it delimiting dash?
JNZ NEXT_PARSE ;If no, find parameter end.
CMP BP,82H ;Else, is this first dash?
JNZ EVALUATE ;If no, evaluate just the two.
PUSH SI ;Save our position.
CALL GET_NUMBER ;Get the parameter.
POP SI ;Restore our position.
PUSH BX ;Save the number.
JMP SHORT NEXT_INPUT ;Get second parameter.
;----------------------------------------------------------------------;
; If quotes were detected, store up to two characters to be evaluated. ;
;----------------------------------------------------------------------;
CHARACTER: XOR BX,BX ;Assume no characters.
LODSB ;Get a byte.
CMP AL,CR ;End of parameter?
JZ ERROR_EXIT ;If yes, no character; exit.
MOV BL,AL ;Else, store character.
LODSB ;Get next character.
CMP AL,CR ;End of parameter?
JZ GOT_CHAR ;If yes, only one character.
CMP AL,QUOTES ;Is it quotes?
JNZ GET_CHAR ;If no, valid second character.
CMP BYTE PTR [SI],QUOTES ;Is it followed by quotes?
JNZ GOT_CHAR ;If no, not quotes in quotes.
GET_CHAR: MOV BH,AL ;Else, store second character.
XCHG BH,BL ;Swap so in right order.
GOT_CHAR: XOR CX,CX ;Zero out parameter count.
JMP SHORT CONVERT ;Convert the character.
;-------------------------------------------------------------;
; Find range of numbers and display the complementry radices. ;
;-------------------------------------------------------------;
EVALUATE: CALL GET_NUMBER ;Get the parameter.
XOR CX,CX ;Assume only one parameter.
CMP BP,82H ;Where there more than one?
JZ CONVERT ;If no, convert just the one.
POP CX ;Else, retrieve the first one.
CMP CX,BX ;Is it the larger of the two?
JA FIND_RANGE ;If yes, find range.
XCHG BX,CX ;Else, swap numbers.
FIND_RANGE: SUB CX,BX ;Find difference.
CONVERT: INC CX ;Increment by one for "thru".
MOV DI,BX ;Save number to be converted.
OUTPUT: PUSH CX ;Save count to be converted.
CALL DECIMAL_OUTPUT ;Display decimal, hexadecimal,
CALL SPACE_IT ; octal and binary equivalents
CALL HEX_OUTPUT ; with spaces in between.
CALL SPACING
CALL OCTAL_OUTPUT
CALL SPACING
CALL BINARY_OUTPUT
CALL SPACING
CALL ASCII_OUTPUT
MOV DL,CR
CALL PRINT_CHAR
MOV DL,LF
CALL PRINT_CHAR
INC DI ;Get ready for next number.
POP CX ;Retrieve conversion count.
LOOP OUTPUT ;Do them all.
XOR AL,AL ;Exit with ErrorLevel of zero.
JMP SHORT EXIT
;---------------------------------------------------------------------------;
; Exit with syntax message and ErrorLevel of 1 if error, else ErrorLevel 0. ;
;---------------------------------------------------------------------------;
ERROR_EXIT: MOV DX,OFFSET SYNTAX ;Display syntax.
CALL PRINT_STRING
MOV AL,1 ;ErrorLevel one.
EXIT: MOV AH,4CH
INT 21H ;Terminate.
MAIN ENDP
; *************
; *SUBROUTINES*
; *************
;------------------------------------------------------------------------------;
; INPUT: SI points to byte after parameter end; BP points to parameter start. ;
; OUTPUT: BX = number. ;
; CALLS: DECIMAL_INPUT, HEX_INPUT, OCTAL_INPUT, BINARY_INPUT. ;
;------------------------------------------------------------------------------;
GET_NUMBER PROC NEAR
DEC SI ;Adjust pointer to parameter end.
MOV CX,SI ;Save SI.
MOV SI,BP ;Point to parameter start.
NEXT_CAP: CMP SI,CX ;Are we end of parameter?
JZ STRING_LENGTH ;If yes, done here.
LODSB ;Get a byte.
CMP AL,"a"
JB NEXT_CAP
CMP AL,"z"
JA NEXT_CAP
AND BYTE PTR [SI-1],5FH ;Capitalize.
JMP SHORT NEXT_CAP
STRING_LENGTH: MOV SI,BP ;Point to parameter start.
SUB CX,BP ;Find parameter length.
PUSH CX ;Save it.
NEXT_RADIX: XCHG CX,BX ;Save count in BX.
LODSB ;Get a byte.
MOV CX,RADIX_CNT ;Count of radix appendixes in CX.
MOV DI,OFFSET RADIX_TYPE ;Point to appendixes.
REPNZ SCASB ;Is it an appendix?
JZ INPUT ;If yes, evaluate.
XCHG CX,BX ;Else, retrieve parameter count.
LOOP_RADIX: LOOP NEXT_RADIX ;Check next byte.
MOV CX,RADIX_CNT ;If no appendix, assume decimal.
INPUT: SHL CX,1 ;Convert count to word pointer.
MOV DI,OFFSET CALLS_END ;Point to input calls end.
SUB DI,CX ;Point to appropriate call.
POP CX ;Retrieve parameter length.
MOV SI,BP ;Point to parameter start.
XOR BX,BX ;Start with a zero number.
CALL [DI] ;Get the number.
MOV DX,OFFSET INVALID_MSG ;Print error message if
JNC END_NUMBER ; number invalid.
CALL PRINT_STRING
JMP SHORT ERROR_EXIT
END_NUMBER: RET ;Else, return with number in BX.
GET_NUMBER ENDP
;----------------------------------------------------------------------;
; INPUT: SI points to parameter start; CX = parameter length; BX = 0. ;
; OUTPUT: BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
;----------------------------------------------------------------------;
DECIMAL_INPUT PROC NEAR
NEXT_DECIMAL: LODSB ;Get a character.
SUB AL,"0" ;ASCII to binary.
JC LOOP_DECIMAL ;If not between 0 and 9, skip.
CMP AL,9
JA LOOP_DECIMAL
CBW ;Convert to word.
XCHG AX,BX ;Swap old and new number.
PUSH CX ;Preserve counter.
MOV CX,10 ;Shift to left by multiplying
MUL CX ; last entry by ten.
POP CX ;Retrieve counter.
JC END_DECIMAL ;If carry, too big.
ADD BX,AX ;Add new number and store in BX.
JC END_DECIMAL ;If carry, too big.
LOOP_DECIMAL: LOOP NEXT_DECIMAL
CLC
END_DECIMAL: RET
DECIMAL_INPUT ENDP
;-----------------------------------------------------------------------;
; INPUT : SI points to parameter start; CX = parameter length; BX = 0. ;
; OUTPUT : BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
;-----------------------------------------------------------------------;
BINARY_INPUT PROC NEAR
NEXT_BIN: LODSB ;Get a byte.
SUB AL,"0" ;ASCII to binary.
JC LOOP_BIN ;If not 0 or 1, skip.
CMP AL,1
JA LOOP_BIN
SHL BX,1 ;Shift old number left one bit.
JC END_BIN ;If carry, too big.
OR BL,AL ;Else, add it to the number.
LOOP_BIN: LOOP NEXT_BIN
CLC
END_BIN: RET
BINARY_INPUT ENDP
;-----------------------------------------------------------------------;
; INPUT : SI points to parameter start; CX = parameter length; BX = 0. ;
; OUTPUT : BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
;-----------------------------------------------------------------------;
HEX_INPUT PROC NEAR
NEXT_HEX: LODSB ;Get a byte.
SUB AL,"0" ;ASCII to binary.
JC LOOP_HEX ;If not 0 to 9, skip.
CMP AL,9 ;Is it A - F ?
JLE NOT_ALPHA ;If no, OK.
SUB AL,7 ;Else, adjust for alpha.
CMP AL,10 ;Is it punctuation?
JB LOOP_HEX ;If yes, skip.
CMP AL,15 ;Is it valid?
JA LOOP_HEX ;If no, skip.
NOT_ALPHA: TEST BX,1111b SHL 12 ;Is the number going to overflow?
STC ;Assume yes.
JNZ END_HEX ;If yes, too big.
PUSH CX ;Else, preserve counter.
MOV CL,4 ;Shift old number four bits left.
SHL BX,CL
POP CX ;Retrieve counter.
OR BL,AL ;Add to number.
LOOP_HEX: LOOP NEXT_HEX
CLC
END_HEX: RET
HEX_INPUT ENDP
;-----------------------------------------------------------------------;
; INPUT : SI points to parameter start; CX = parameter length; BX = 0. ;
; OUTPUT : BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
;-----------------------------------------------------------------------;
OCTAL_INPUT PROC NEAR
NEXT_OCTAL: LODSB ;Get a byte.
SUB AL,"0" ;ASCII to binary.
JC LOOP_OCTAL ;If not 0 through 7, skip.
CMP AL,7
JA LOOP_OCTAL
TEST BX,111b SHL 13 ;Is the number going to overflow?
STC ;Assume yes.
JNZ END_OCTAL ;If yes, too big.
PUSH CX ;Else, save counter.
MOV CL,3 ;Shift old number left three bits
SHL BX,CL
POP CX ;Retrieve counter.
OR BL,AL ;Add to number.
LOOP_OCTAL: LOOP NEXT_OCTAL
CLC
END_OCTAL: RET
OCTAL_INPUT ENDP
;-----------------------------------------------------------------------;
; INPUT : SI points to parameter start; CX = parameter length; BX = 0. ;
; OUTPUT : BX = number; CY = 0 if valid entry; CY = 1 if invalid entry. ;
;-----------------------------------------------------------------------;
DECIMAL_OUTPUT PROC NEAR
MOV AX,DI ;Retrieve number.
MOV BX,10 ;Divisor of ten.
XOR CX,CX ;Zero in counter.
NEXT_COUNT: XOR DX,DX ;Zero in high half.
DIV BX ;Divide by ten.
ADD DL,"0" ;Convert to ASCII.
PUSH DX ;Save results.
INC CX ;Also increment count.
CMP AX,0 ;Are we done?
JNZ NEXT_COUNT ;Continue until zero.
MOV BX,CX ;Save the number of characters.
NEXT_NUMBER: POP DX ;Retrieve numbers.
CALL PRINT_CHAR ;And write them.
LOOP NEXT_NUMBER
MOV CX,SPACE_CNT + 5 ;Return with tab count.
SUB CX,BX
RET
DECIMAL_OUTPUT ENDP
;----------------------------------------;
; INPUT: DI = number. ;
;----------------------------------------;
HEX_OUTPUT PROC NEAR
MOV BX,DI ;Retrieve number.
MOV CX,404H ;4 positions/word; 4bits/char.
ROTATE_HEX: ROL BX,CL ;Move highest bits to lowest.
MOV DL,BL
AND DL,1111B ;Mask off all but four lowest.
ADD DL,"0" ;Convert to ASCII.
CMP DL,"9" ;Is it alpha.
JLE PRINT_HEX ;If no, print it.
ADD DL,7 ;Else, adjust.
PRINT_HEX: CALL PRINT_CHAR ;And write them.
DEC CH ;Done all four positions?
JNZ ROTATE_HEX ;If no, get next.
MOV DL,"h" ;Tack on hex character.
CALL PRINT_CHAR
RET
HEX_OUTPUT ENDP
;----------------------------------------;
; INPUT: DI = number. ;
;----------------------------------------;
OCTAL_OUTPUT PROC NEAR
MOV BX,DI ;Retrieve number.
MOV CX,603H ;6 positions/word; 3bits/char.
ROL BX,1 ;Special case first; get top bit.
MOV DL,BL
AND DL,1 ;Mask off all but that bit.
JMP SHORT OCTAL_ASCII ;Write it.
OCTAL_ROTATE: ROL BX,CL ;Rotate highest 3 bits to lowest.
MOV DL,BL
AND DL,111B ;Mask off all but lowest 3 bits.
OCTAL_ASCII: ADD DL,"0" ;Convert to ASCII.
CALL PRINT_CHAR ;Write it.
DEC CH ;Do all 6 positions.
JNZ OCTAL_ROTATE
MOV DL,"o" ;Tack on octal character.
CALL PRINT_CHAR
RET
OCTAL_OUTPUT ENDP
;----------------------------------------;
; INPUT: DI = number. ;
;----------------------------------------;
BINARY_OUTPUT PROC NEAR
MOV BX,DI ;Retrieve number.
MOV CH,16 ;Display all 16 positions.
ROTATE_BIN: ROL BX,1 ;Move highest bit to lowest.
MOV DL,BL
AND DL,1 ;Mask off all but lowest.
ADD DL,"0" ;Convert to ASCII.
CALL PRINT_CHAR
CMP CH,9 ;Format with space between bytes.
JNZ SKIP_SPACE
MOV DL,SPACE
CALL PRINT_CHAR
SKIP_SPACE: DEC CH ;Do all 16 bits.
JNZ ROTATE_BIN
MOV DL,"b" ;Tack on binary character.
CALL PRINT_CHAR
RET
BINARY_OUTPUT ENDP
;----------------------------------------;
; INPUT: DI = number. ;
;----------------------------------------;
ASCII_OUTPUT PROC NEAR
XOR BH,BH ;Page zero.
MOV AX,0E22H ;Write TTY a quote mark.
INT 10H ; via BIOS.
MOV CX,3 ;Display 3 quotation marks and
MOV AX,0A22H ; do not update cursor position.
INT 10H
MOV CX,2 ;Display the low byte twice
MOV AX,DI
MOV AH,0AH ; at current cursor position.
INT 10H
MOV CX,1 ;Display the high byte once
MOV AX,DI ; at current cursor position
XCHG AL,AH
MOV AH,0AH ; over the first low byte.
INT 10H
RET
ASCII_OUTPUT ENDP
;---------------------------------------------------------------;
; These subroutines print and separate the display with spaces. ;
;---------------------------------------------------------------;
PRINT_CHAR PROC NEAR
MOV AH,2 ;DOS display output.
INT 21H ;Character is in DL.
RET
PRINT_CHAR ENDP
;-------------------------;
PRINT_STRING PROC NEAR
MOV AH,9 ;DOS string output.
INT 21H ;DX points to string
RET ; terminated by "$".
PRINT_STRING ENDP
;-------------------------;
SPACING PROC NEAR
MOV CX,SPACE_CNT ;Retrieve space count between
SPACE_IT: MOV DL,SPACE ; outputs and print via DOS.
CALL PRINT_CHAR
LOOP SPACE_IT
RET
SPACING ENDP
_TEXT ENDS
END START